/*
 * tcp_output.c
 *
 *  Created on: 2009-5-14
 *      Author: tian
 */

#include"mytcp.h"

int tcp_output(struct tcphdr *ptcpheader,char *buf,unsigned int buflen,struct tcpcb* ptcpcb){
	if(ptcpcb==NULL){
		fprintf(stderr,"tcpcb is null\n");
		return -1;
	}

	ptcpheader->tcp_seq=ptcpcb->seq++;
	ptcpheader->tcp_hl_flag.hl=sizeof(struct tcphdr)/2;
	/*windows==1,send and wait? arq*/
	ptcpheader->tcp_hl_flag.tcp_win=1;
	if(ptcpheader->tcp_hl_flag.ack==1)
		ptcpheader->tcp_ack=ptcpcb->peerseq;
	struct ip_fake_hdr ipfhdr;
	struct iphdr ipheader;
	char tcppkg[BUFLEN-20]={0};
	int i=0;
	int j=0;

	/*combine tcp header and data*/
	for(;i<sizeof(struct tcphdr);i++)
		tcppkg[i]=*((char *)ptcpheader+i);
	for(;j<buflen;j++)
		tcppkg[i+j]=buf[j];

    /*calculate tcp check sum*/
	ipfhdr.des=ptcpcb->sock_addr.peer_ip;
	ipfhdr.src=ptcpcb->sock_addr.my_ip;
	ipfhdr.mbz=0;
	ipfhdr.pro=PROTOCOL_TCP;
	ipfhdr.tcp_l=sizeof(struct tcphdr)+buflen;

	//((struct tcphdr*)tcppkg)->tcp_sum=tcp_checksum(&ipfhdr,tcppkg);
	int sum=tcp_checksum(&ipfhdr,tcppkg);
	((struct tcphdr*)tcppkg)->tcp_sum=sum;
	//for test
		struct tcphdr th=*((struct tcphdr*)tcppkg);
		printf("in tcp_output:sumcal:%d\n",sum);
		printf("sport:%d,dport:%d,",th.tcp_sport,th.tcp_dport);
		printf("sum:%d,seq:%ld,ack:%ld\n",th.tcp_sum,th.tcp_seq,th.tcp_ack);
		printf("syn:%d,ack:%d,fin:%d\n",th.tcp_hl_flag.syn,th.tcp_hl_flag.ack,th.tcp_hl_flag.fin);

    /*create ip header and fill it*/
	ipheader.des=ipfhdr.des;
	ipheader.src=ipfhdr.src;
	ipheader.ip_id.ip_id=DEFAULT_ID;
	ipheader.ip_verhl.ip_len=DEFAULT_IP_HEADER_LENGTH/8+DEFAULT_TCP_HEADER_LENGTH/8+buflen;
	ipheader.ip_pro=PROTOCOL_TCP;
	ipheader.ip_verhl.ip_tos=DEFAULT_TOS;
	ipheader.ip_ttl=DEFAULT_TTL;
	ipheader.ip_sum=0;
	ipheader.ip_verhl.ip_hl=DEFAULT_IP_HEADER_LENGTH/16;
	ipheader.ip_verhl.ip_ver=DEFAULT_IP_VERSION;
	/*call ip_output to send package*/
	if(ip_output(&ipheader,(char *)tcppkg,sizeof(struct tcphdr)+buflen)<0){
		fprintf(stderr,"call ip_output() error in tcp_output\n");
		return -1;
	}
	/*save last package*/
	ptcpcb->lasthdr=*ptcpheader;
	ptcpcb->sndlen=buflen;
	/*set timer*/
	if(ptcpheader->tcp_hl_flag.ack!=1)
		ptcpcb->timer[1]=3;
	return 0;
}
